package com.xbongbong.saas.factory.publicrule;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.CustomerErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.domain.entity.ClueRuleEntity;
import com.xbongbong.saas.domain.entity.RuleClueEntity;
import com.xbongbong.saas.domain.entity.ext.ClueEntityExt;
import com.xbongbong.saas.enums.ChildClueRuleEnum;
import com.xbongbong.saas.enums.ClueRuleChildEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ClueEnum;
import com.xbongbong.saas.model.ClueModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.sys.domain.entity.UserEntity;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author long
 * @version v1.0
 * @date 2020/12/2 15:37
 * @since v1.0
 */
@Component
public class CheckRuleMaxClueNum extends AbstractCheckClueRule implements ICheckClueRule{

    @Resource
    private ClueModel clueModel;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private EsHelper esHelper;
    @Resource
    private IndexTypeModel indexTypeModel;

    private Integer noBack = 1;
    private Integer clueTypeBack = 2;
    private Integer maxStatus = 5;
    public CheckRuleMaxClueNum(){
    }

    @Override
    public boolean canGainClue(ClueRuleEntity rule, String corpid, UserEntity userEntity, Long clueId, int dataIdSize, JSONObject data) throws XbbException {
        //没有规则，不限制线索获取
        if(rule == null || Objects.equals(rule.getStatus(), 0)){
            return true;
        }
        ClueEntityExt clueEntity;
        if (Objects.isNull(clueId) || Objects.equals(clueId, 0L)) {
            clueEntity = new ClueEntityExt();
            clueEntity.setData(data);
        } else {
            clueEntity = clueModel.getByKey(clueId, corpid);
        }
        /**
         * rule.getRuleType() 必然是 CustomerRuleEnum.MAX_CUSTOMER_NUM_RULE.getCode()
         */
        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
        JSONObject ruleValueJson = (JSONObject) operateRuleValue.toObject(rule);

        //判断超过最大线索拥有数时是否允许捞取
        JSONObject backRuleJson = ruleValueJson.getJSONObject("backRule");
        Integer backType = backRuleJson.getInteger("backType");

        //根据线索状态自动退回     根据线索重要程度自动退回

        if(Objects.equals(backType, clueTypeBack)){
            return true;
        }

        if(!Objects.equals(backType, noBack)){
            throw new XbbException(CustomerErrorCodeEnum.API_ERROR_201032);
        }
        String status = clueEntity.getData().getString(ClueEnum.CLUE_STATUS.getAttr());

        List<String> typeNotIn = JSON.parseArray(ruleValueJson.getJSONArray("clueStatus").toJSONString(), String.class);

        List<Long> labelNotIn = JSON.parseArray(ruleValueJson.getJSONArray("label").toJSONString(), Long.class);

        labelNotIn = Objects.isNull(labelNotIn) ? new ArrayList<>() : labelNotIn;

        if (notBackClue(clueEntity, typeNotIn)) {
            return true;
        }

        if (notBackClue4Label(clueEntity, labelNotIn)) {
            return true;
        }

        Integer type = ruleValueJson.getInteger("type");
        if (Objects.equals(type, ClueRuleChildEnum.LABEL.getCode())) {
            Map<Long, Integer> mainDayMap = getMinDayMap(ruleValueJson.getJSONArray("restrict"), userEntity);
            String labelStr = clueEntity.getData().getString(ClueEnum.LABEL.getAttr());
            List<Long> labels = JSON.parseArray(labelStr, Long.class);
            labels = Objects.isNull(labels) ? new ArrayList<>() : labels;
            if (CollectionsUtil.isNotEmpty(labels)) {
                labels.removeAll(labelNotIn);
            }
            Iterator<Map.Entry<Long, Integer>> iterator = mainDayMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Long, Integer> next = iterator.next();
                Long key = next.getKey();
                if (labelNotIn.contains(key) || !labels.contains(key)) {
                    // 勾选的不退回的标签或当前线索的标签不一样的都去掉
                    iterator.remove();
                }
            }

            return getClueCountByLabels(corpid, userEntity.getUserId(), typeNotIn, labelNotIn, mainDayMap);
        } else {
            //获取当前用户的最小配置
            /**
             * key:value
             * {"1":2,"2":6,"3":5}
             */
            JSONObject minObject = getMinObject(ruleValueJson.getJSONArray("restrict"), userEntity, type);

            Set<String> keySet = minObject.keySet();
            for (String key : keySet) {
                if (!Objects.equals(key, "0") && !Objects.equals(key, status)) {
                    continue;
                }
                Integer minValue = minObject.getInteger(key);
                Integer clueCount = getClueCount(corpid, userEntity.getUserId(), typeNotIn, labelNotIn, key);
                if (clueCount + dataIdSize > minValue) {
                    return false;
                }
            }
        }
        return true;
    }

    public Map<Long, Integer> getMinDayMap(JSONArray restrict, UserEntity userEntity) {
        Map<Long, Integer> specialMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Integer> allMinDayMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> deptIds;
        try {
            deptIds = JSONArray.parseArray(userEntity.getDepartment(), Long.class);
        } catch (Exception e) {
            deptIds = new ArrayList<>();
        }
        if (deptIds == null) {
            deptIds = new ArrayList<>();
        }
        List<Integer> roleIds = new ArrayList<>();
        String role = userEntity.getRoleIds();
        if (StringUtil.isNotEmpty(role)) {
            roleIds = StringUtil.roleIdToListInt(role);
        }
        if (roleIds == null) {
            roleIds = new ArrayList<>();
        }
        for(Object restrictObject : restrict){
            JSONObject restrictJson = (JSONObject)restrictObject;
            JSONArray users = restrictJson.getJSONArray("users");
            JSONArray depts = restrictJson.getJSONArray("depts");
            JSONArray roles = restrictJson.getJSONArray("roles");
            List<String> userIdList = new ArrayList<>();
            List<Long> deptIdList = new ArrayList<>();
            List<Integer> roleIdList = new ArrayList<>();
            if (Objects.nonNull(users)) {
                userIdList = JSON.parseArray(users.toJSONString(), String.class);
            }
            if (Objects.nonNull(depts)) {
                deptIdList = JSON.parseArray(depts.toJSONString(), Long.class);
            }
            if (Objects.nonNull(roles)) {
                roleIdList = JSON.parseArray(roles.toJSONString(), Integer.class);
            }
            deptIdList.retainAll(deptIds);
            roleIdList.retainAll(roleIds);
            Boolean scecialConfig = users != null || depts != null || roles != null;
            Boolean configFail = !userIdList.contains(userEntity.getUserId()) && deptIdList.isEmpty() && roleIdList.isEmpty();
            if(scecialConfig && configFail){
                //对于当前用户无效的配置
                continue ;
            }

            JSONArray array = restrictJson.getJSONArray("array");

            stringKey(array, users, depts, roles, specialMinDayMap, allMinDayMap);
        }
        Iterator<Map.Entry<Long, Integer>> it = allMinDayMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Long, Integer> entry = it.next();
            Long key = entry.getKey();

            Integer integer = specialMinDayMap.get(key);
            if (Objects.nonNull(integer)) {
                // 如果某个标签出现在全部和特殊里面，那么去掉全部的标签配置；
                it.remove();
            }
        }
        specialMinDayMap.putAll(allMinDayMap);
        return specialMinDayMap;
    }

    private void stringKey(JSONArray array, JSONArray users, JSONArray depts, JSONArray roles, Map<Long, Integer> specialMinDayMap, Map<Long, Integer> allMinDayMap) {
        for(Object object : array){
            JSONObject jsonObject = (JSONObject)object;
            String key = jsonObject.getString("key");

            List<Long> labels = JSON.parseArray(key, Long.class);

            Integer value = jsonObject.getInteger("value");

            if(users == null && depts == null && roles == null){
                for (Long label : labels) {
                    Integer integer = allMinDayMap.get(label);
                    if (Objects.isNull(integer)) {
                        allMinDayMap.put(label, value);
                        continue;
                    }
                    if (integer < value) {
                        allMinDayMap.put(label, integer);
                    }
                }
                continue ;
            }

            for (Long label : labels) {
                Integer integer = specialMinDayMap.get(label);
                if (Objects.isNull(integer)) {
                    specialMinDayMap.put(label, value);
                    continue;
                }
                if (integer < value) {
                    specialMinDayMap.put(label, integer);
                }
            }
        }
    }

    /**
     * @Description:获取线索数
     * @param corpid 公司id
     * @param userId 所属人
     * @param typeNotIn 排除的状态
     * @return
     */
    public Integer getClueCount(String corpid, String userId, List<String> typeNotIn, List<Long> labelNotIn, String key){
        Integer count = 0;
        try {
            Integer del = 0;
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            //解析查询条件
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery("del", del));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
            if(typeNotIn != null && typeNotIn.size() > 0){
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery("data." + ClueEnum.CLUE_STATUS.getAttr(), typeNotIn)));
            }
            if(labelNotIn != null && labelNotIn.size() > 0){
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.LABEL), labelNotIn)));
            }
            if (!Objects.equals(key, "0")) {
                boolQueryBuilder.filter(termQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.CLUE_STATUS), key));
            }
            IndexTypeEnum customerTeamIndex = indexTypeModel.getCustomerTeamIndex(corpid, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode(), SaasMarkEnum.SAAS.getCode());
            HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(customerTeamIndex, corpid, BasicConstant.ONE, Arrays.asList(userId));
            boolQueryBuilder.filter(hasChildQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            sourceBuilder.query(boolQueryBuilder);
            searchRequest.source(sourceBuilder);
            CountRequest countRequest = new CountRequest(searchRequest.indices()[0]);
            countRequest.query(searchRequest.source().query());
            count = Math.toIntExact(xbbElasticsearchRestTemplate.count(countRequest));
        } catch (Exception e) {

        }
        return count;

    }

    /**
     * @Description:获取线索数
     * @param corpid 公司id
     * @param userId 所属人
     * @param typeNotIn 排除的状态
     * @return
     */
    public boolean getClueCountByLabels(String corpid, String userId, List<String> typeNotIn, List<Long> labelNotIn, Map<Long, Integer> minMap) {
        boolean canGainClue = true;
        if (minMap.isEmpty()) {
            return canGainClue;
        }
        try {

            Integer del = 0;
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            BoolQueryBuilder boolQueryBuilder = boolQuery();
            //解析查询条件
            boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
            boolQueryBuilder.filter(termQuery("del", del));
            HasChildQueryBuilder hasChildQueryBuilder = esHelper.teamQueryBuilder(IndexTypeEnum.IDX_SAAS_CLUE_TEAM, corpid, BasicConstant.ONE, Arrays.asList(userId));
            boolQueryBuilder.filter(hasChildQueryBuilder);
            if(typeNotIn != null && typeNotIn.size() > 0){
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery("data." + ClueEnum.CLUE_STATUS.getAttr(), typeNotIn)));
            }
            if(labelNotIn != null && labelNotIn.size() > 0){
                boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.LABEL), labelNotIn)));
            }
            boolQueryBuilder.filter(termsQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.LABEL), minMap.keySet()));
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));

            //拿固定数据
            sourceBuilder.fetchSource(ClueEnum.getAttrConnectData(ClueEnum.LABEL),null);
            sourceBuilder.query(boolQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
            PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 10000);
            searchRequest.source(sourceBuilder);
            XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);

            List<PaasFormDataEntityExt> content = esEntities.getContent();
            Map<Long, Integer> realLabelIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (PaasFormDataEntityExt entityExt : content) {
                String labelStr = entityExt.getData().getString(ClueEnum.LABEL.getAttr());
                List<Long> labels = JSON.parseArray(labelStr, Long.class);
                if (CollectionsUtil.isEmpty(labels)) {
                    continue;
                }
                for (Long label : labels) {
                    Integer num = realLabelIdAndNum.get(label);
                    if (Objects.isNull(num)) {
                        num = 1;
                    } else {
                        num++;
                    }
                    realLabelIdAndNum.put(label, num);
                }
            }
            for (Map.Entry<Long, Integer> entry : minMap.entrySet()) {
                Long key = entry.getKey();
                Integer value = entry.getValue();
                Integer num = realLabelIdAndNum.getOrDefault(key, 0);
                if (Objects.nonNull(num) && num >= value) {
                    // 如果拥有的线索数量大约等于配置的数量，那么就超过了拥有线索最大数了
                    canGainClue = false;
                    break;
                }

            }
        } catch (Exception e) {

        }
        return canGainClue;

    }

    @Override
    public List<RuleClueEntity> getBackClueList(UserEntity userEntity,
                                                        ClueRuleEntity rule, List<RuleClueEntity> clueList,
                                                        Integer advanceTime) throws XbbException {
        return new ArrayList<>();
    }

    @Override
    public List<RuleClueEntity> getBackClueList(UserEntity userEntity,
                                                        ClueRuleEntity rule, List<RuleClueEntity> clueList)
            throws XbbException {

        List<RuleClueEntity> retList = new ArrayList<>();
        if (rule == null || Objects.equals(rule.getStatus(), 0)) {
            return retList;
        }

        IOperateClueRuleValue operateRuleValue = OperateClueRuleValueFactory.operateRuleValueFactory(rule.getRuleType());
        Object ruleValueObject = operateRuleValue.toObject(rule);
        JSONObject ruleValueJson = (JSONObject) ruleValueObject;

        //判断退回规则
        JSONObject backRule = ruleValueJson.getJSONObject("backRule");
        Integer backType = backRule.getInteger("backType");
        //不自动退回
        if (Objects.equals(backType, 1)) {
            return retList;
        }

        Integer type = ruleValueJson.getInteger("type");

        List<Long> labelNotIn = JSON.parseArray(ruleValueJson.getJSONArray("label").toJSONString(), Long.class);
        labelNotIn = Objects.isNull(labelNotIn) ? new ArrayList<>() : labelNotIn;
        List<String> typeNotIn = JSON.parseArray(ruleValueJson.getJSONArray("clueStatus").toJSONString(), String.class);

        if (Objects.equals(type, ClueRuleChildEnum.LABEL.getCode())) {

            removeRuleNoBack(clueList, typeNotIn);

            removeRuleLabelNoBack(clueList, labelNotIn);

            Map<Long, Integer> minDayMap = getMinDayMap(ruleValueJson.getJSONArray("restrict"), userEntity);
            Iterator<Map.Entry<Long, Integer>> iterator = minDayMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Long, Integer> next = iterator.next();
                Long key = next.getKey();
                if (labelNotIn.contains(key)) {
                    // 勾选的不退回的标签或当前线索的标签不一样的都去掉
                    iterator.remove();
                }
            }
            JSONArray sort = backRule.getJSONArray("sort");
            return getBackClues(minDayMap, clueList, userEntity.getCorpid(), sort);
        } else {

            //获取当前用户的最小配置
            /**
             * key:value
             * {"1":2,"2":6,"3":5}
             */
            JSONObject minObject = getMinObject(ruleValueJson.getJSONArray("restrict"), userEntity, type);

            //判断没有移除线索前是否超过最大线索数规则限制
            if (!moreThanRuleNum(userEntity, type, minObject)) {
                return retList;
            }

            removeRuleNoBack(clueList, typeNotIn);

            removeRuleLabelNoBack(clueList, labelNotIn);

            List<Long> clueIdIn = new ArrayList<>();
            for (RuleClueEntity clue : clueList) {
                clueIdIn.add(clue.getId());
            }
            //获取需要退回公海池的线索数,记录每种类型的截取信息
            JSONObject moreCountObject = new JSONObject();
            if (Objects.equals(type, ChildClueRuleEnum.CLUE_ALL.getCode())) {
                Integer moreCount = 0;
                Integer minCount = (Integer) minObject.get("0");
                Integer count = clueList.size();
                if (minCount != null && count > minCount) {
                    moreCount = count - minCount;
                }

                JSONObject pageJson = new JSONObject();
                pageJson.put("start", 0);
                pageJson.put("pageNum", moreCount);

                moreCountObject.put("0", pageJson);
            } else if (Objects.equals(type, ChildClueRuleEnum.CLUE_STATUS.getCode())) {
                for (int i = 1; i < maxStatus; i++) {
                    Integer moreCount = 0;
                    String statuStr = i + "";
                    Integer minCount = (Integer) minObject.get(statuStr);

                    Integer count = clueModel.getMainClueCountByUserId(userEntity.getCorpid(), userEntity.getUserId(), statuStr);
                    if (minCount != null && count > minCount) {
                        moreCount = count - minCount;
                    }
                    JSONObject pageJson = new JSONObject();
                    pageJson.put("start", 0);
                    pageJson.put("pageNum", moreCount);
                    moreCountObject.put(i + "", pageJson);
                }
            }

            //获取退回顺序
            String orderField = null;

            JSONArray sort = backRule.getJSONArray("sort");
            List<Integer> sortList = new ArrayList<>();
            if (Objects.nonNull(sort)) {
                sortList = sort.toJavaList(Integer.class);
            }

            if (Objects.equals(backType, clueTypeBack)) {
                if (CollectionsUtil.isNotEmpty(sortList)) {
                    orderField = ClueEnum.getAttrConnectData(ClueEnum.CLUE_STATUS);
                }
                if (CollectionsUtil.isNotEmpty(sortList)) {
                    sortList.add(0, 0);
                }

                if (Objects.equals(type, ChildClueRuleEnum.CLUE_ALL.getCode())) {
                    JSONObject pageJson = moreCountObject.getJSONObject("0");
                    Integer pageNum = null;
                    Integer pageSize = null;
                    if (pageJson != null) {
                        pageNum = 1;
                        pageSize = pageJson.getInteger("pageNum");
                    }

                    retList.addAll(clueModel.getMainClueListByUserId(userEntity.getCorpid(), userEntity.getUserId(), null, pageNum, pageSize, orderField, sortList, clueIdIn));
                } else if (Objects.equals(type, ChildClueRuleEnum.CLUE_STATUS.getCode())) {
                    for (int i = 1; i < maxStatus + 1; i++) {
                        String status = i + "";
                        JSONObject pageJson = moreCountObject.getJSONObject(status);
                        Integer pageNum = null;
                        Integer pageSize = null;
                        if (pageJson != null) {
                            pageNum = 1;
                            pageSize = pageJson.getInteger("pageNum");
                        }
                        retList.addAll(clueModel.getMainClueListByUserId(userEntity.getCorpid(), userEntity.getUserId(), status, pageNum, pageSize, orderField, sortList, clueIdIn));
                    }
                }
            }
            return retList;
        }
    }

    private List<RuleClueEntity> getBackClues(Map<Long, Integer> minDayMap, List<RuleClueEntity> clueList, String corpid, JSONArray sortArr) throws XbbException{
        List<RuleClueEntity> clues = new ArrayList<>();
        if (minDayMap.isEmpty()) {
            return clues;
        }
        List<Long> clueIdIn = new ArrayList<>();
        for (RuleClueEntity clue : clueList) {
            clueIdIn.add(clue.getId());
        }
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        //解析查询条件
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termsQuery("dataId", clueIdIn));
        boolQueryBuilder.filter(termsQuery(ClueEnum.getEsAttr4Keyword(ClueEnum.LABEL), minDayMap.keySet()));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,IndexTypeEnum.IDX_SAAS_CLUE.getType()));
        List<String> fieldList = Arrays.asList(ClueEnum.LABEL.getAttr(), ClueEnum.CLUE_STATUS.getAttr(), FieldTypeEnum.DATAID.getAlias());
        //拿固定数据
        EsUtil.setFieldList(sourceBuilder, fieldList);
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CLUE.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, clueIdIn.size());
        searchRequest.source(sourceBuilder);

        XbbAggregatedPage<PaasFormDataEntityExt> esEntities =  xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest,PaasFormDataEntityExt.class);

        List<PaasFormDataEntityExt> content = esEntities.getContent();
        Map<Long, Integer> labelIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        Map<String, List<PaasFormDataEntityExt>> entityMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (PaasFormDataEntityExt entityExt : content) {
            String status = entityExt.getData().getString(ClueEnum.CLUE_STATUS.getAttr());
            if (StringUtil.isEmpty(status)) {
                continue;
            }
            List<PaasFormDataEntityExt> orDefault = entityMap.getOrDefault(status, new ArrayList<>());
            orDefault.add(entityExt);
            entityMap.put(status, orDefault);
        }

        List<String> list = JSONArray.parseArray(sortArr.toJSONString(), String.class);
        // 因为排在上面的优先退回，所以这边倒叙处理，就能实现后面出现的数据退回的概率比前面小
        Collections.reverse(list);
        List<PaasFormDataEntityExt> exts = new ArrayList<>();
        for (String str : list) {
            List<PaasFormDataEntityExt> entityExts = entityMap.get(str);
            if (CollectionsUtil.isNotEmpty(entityExts)) {
                exts.addAll(entityExts);
            }
        }
        List<Long> idIn = new ArrayList<>();
        for (PaasFormDataEntityExt entityExt : exts) {
            String status = entityExt.getData().getString(ClueEnum.CLUE_STATUS.getAttr());
            if (StringUtil.isEmpty(status)) {
                continue;
            }
            String labelStr = entityExt.getData().getString(ClueEnum.LABEL.getAttr());
            List<Long> labels = JSON.parseArray(labelStr, Long.class);
            if (CollectionsUtil.isEmpty(labels)) {
                continue;
            }
            for (Long label : labels) {
                Integer num = labelIdAndNum.get(label);
                if (Objects.isNull(num)) {
                    num = 1;
                } else {
                    num++;
                }
                Integer minNum = minDayMap.get(label);
                if (Objects.nonNull(minNum) && num > minNum) {
                    idIn.add(entityExt.getDataId());
                }
                labelIdAndNum.put(label, num);
            }
        }
        if (CollectionsUtil.isNotEmpty(idIn)) {
            clues = clueModel.getClueListByIdIn(corpid, idIn);
        }
        return clues;
    }


    /**
     * @Description: 判断未移除线索前，拥有线索是否超过规则限制
     * @param userEntity
     * @param type
     * @param minObject
     * @return
     */
    private boolean moreThanRuleNum(UserEntity userEntity, Integer type,
                                    JSONObject minObject) {
        //没有限制
        if(minObject == null){
            return false;
        }
        if(Objects.equals(type, ChildClueRuleEnum.CLUE_ALL.getCode())) {
            Integer minNum = (Integer) minObject.get("0");

            if(minNum == null){
                return false;
            }

            Integer count = clueModel.getMainClueCountByUserId(userEntity.getCorpid(), userEntity.getUserId());
            if(count > minNum){
                return true;
            }
        } else if(Objects.equals(type, ChildClueRuleEnum.CLUE_STATUS.getCode())) {
            Set<String> set = minObject.keySet();
            for(String key : set){
                Integer minNum = (Integer) minObject.get(key);
                Integer count = clueModel.getMainClueCountByUserId(userEntity.getCorpid(), userEntity.getUserId(), key);
                if(count > minNum){
                    return true;
                }
            }
        }
        return false;
    }
}

